package de.hsowl.tod4a.global.crypto;

import de.hsowl.tod4a.global.variables.GlobalFlags;

/**
 * Basic en-/decryption interface
 * 
 * @author Sebastian Witt
 * 
 */
public class CryptoUnit {

	public static final int DEFAULT_ROUNDS = 1;
	private final static String HEX = "0123456789ABCDEF";
	public static final byte AES_128 = 100;
	public static final byte AES_192 = 101;
	public static final byte AES_256 = 102;

	/**
	 * Decrypts a String
	 * 
	 * @param key
	 * @param encrypted
	 * @param method
	 * @return
	 */
	public static synchronized String decrypt(String key, String encrypted, int method) {
		byte[] decrypted = decrypt(key.getBytes(), toByte(encrypted), DEFAULT_ROUNDS, method);
		return getStringFromByte(decrypted);
	}

	/**
	 * Decrypts a String
	 * 
	 * @param key
	 * @param encrypted
	 * @param method
	 * @return
	 */
	public static synchronized String decrypt(byte[] key, String encrypted, int method) {
		byte[] decrypted = decrypt(key, toByte(encrypted), DEFAULT_ROUNDS, method);
		return getStringFromByte(decrypted);
	}

	/**
	 * Decrypts a String
	 * 
	 * @param key
	 * @param encrypted
	 * @param method
	 * @return
	 */
	public static synchronized byte[] decrypt(byte[] key, byte[] encrypted, int method) {
		return decrypt(key, encrypted, DEFAULT_ROUNDS, method);
	}

	/**
	 * Decrypts a String
	 * 
	 * @param key
	 * @param encrypted
	 * @param runden
	 * @param method
	 * @return
	 */
	public static synchronized byte[] decrypt(byte[] key, byte[] encrypted, int runden, int method) {
		if (encrypted != null) {
			return AES.decrypt(key, encrypted, runden, method);
		}
		return null;
	}

	/**
	 * Encrypts a String as hex value
	 * 
	 * @param key
	 * @param cleartext
	 * @param method
	 * @return
	 */
	public static synchronized String encrypt(String key, String cleartext, int method) {
		byte[] encrypted = encrypt(key.getBytes(), cleartext.getBytes(), DEFAULT_ROUNDS, method);

		return toHex(encrypted);
	}

	/**
	 * Encrypts a String as hex value
	 * 
	 * @param key
	 * @param cleartext
	 * @param method
	 * @return
	 */
	public static synchronized String encrypt(byte[] key, String cleartext, int method) {
		byte[] encrypted = encrypt(key, cleartext.getBytes(), DEFAULT_ROUNDS, method);

		return toHex(encrypted);
	}

	/**
	 * Encrypts a String as hex value
	 * 
	 * @param key
	 * @param cleartext
	 * @param method
	 * @return
	 */
	public static byte[] encrypt(byte[] key, byte[] cleartext, int method) {
		return encrypt(key, cleartext, DEFAULT_ROUNDS, method);
	}

	/**
	 * Encrypts a String as hex value
	 * 
	 * @param key
	 * @param cleartext
	 * @param runden
	 * @param method
	 * @return
	 */
	public static synchronized byte[] encrypt(byte[] key, byte[] cleartext, int runden, int method) {
		return AES.encrypt(key, cleartext, runden, method);
	}

	/**
	 * Encrypts a String as hex value
	 * 
	 * @param toHash
	 * @return
	 */
	public static synchronized String getMD5Hash(String toHash) {
		try {
			return getMD5(toHash, DEFAULT_ROUNDS);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * Hashes a value 'rounds' time
	 * 
	 * @param toHash
	 * @param rounds
	 * @return
	 */
	public static synchronized String getMD5(String toHash, int rounds) {
		try {
			return Message_Digest.getMD5(toHash, rounds);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * Get a String from a byte array
	 * 
	 * @param arr
	 * @return
	 */
	public static synchronized String getStringFromByte(byte[] arr) {
		StringBuffer text = new StringBuffer();
		for (int i = 0; i < arr.length; i++) {
			text.append((char) arr[i]);
		}
		return text.toString();
	}

	/**
	 * Get a hex String from a byte array
	 * 
	 * @param buf
	 * @return
	 */
	public static synchronized String toHex(byte[] buf) {
		try {
			if (buf == null)
				return "";
			StringBuffer result = new StringBuffer(2 * buf.length);

			for (int i = 0; i < buf.length; i++) {
				appendHex(result, buf[i]);
			}

			return new String(result.toString().getBytes(), GlobalFlags.ENCODING);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	private static void appendHex(StringBuffer sb, byte b) {
		sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
	}

	/**
	 * Get a hex String from a String
	 * 
	 * @param txt
	 * @return
	 */
	public static synchronized String toHex(String txt) {
		return toHex(txt.getBytes());
	}

	/**
	 * Get a String from a hex String
	 * 
	 * @param hex
	 * @return
	 */
	public static String fromHex(String hex) {
		return new String(toByte(hex));
	}

	/**
	 * Get a byte array from a hex String
	 * 
	 * @param hexString
	 * @return
	 */
	public static byte[] toByte(String hexString) {
		int len = hexString.length() / 2;
		byte[] result = new byte[len];
		for (int i = 0; i < len; i++)
			result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
		return result;
	}
}
